#ifndef __M_DATA_H__
#define __M_DATA_H__

#include <pthread.h>
#include <unordered_map>
#include "Util.hpp"
#include "config.hpp"
#include "User.hpp"

/*
    备份信息的描述和组织
*/

namespace cloud
{
    typedef struct backupInfo
    {
        bool NewBackupInfo(const std::string real_path,const std::string& name)
        {
            FileUtil file(real_path);
            if (file.IsExist() == false)
            {
                std::cerr << "new BackupInfo fail : file is not exise" << std::endl;
                return false;
            }

            std::string Email = UserManager::GetInstance()->GetEmail(name);

            std::string download_prefix = config::GetInstance()->GetDownloadPrefix();
            std::string pack_path = config::GetInstance()->GetPackDictory() + Email + "/";//加上邮箱作为地址,便于区分哪个用户的文件
            std::string pack_suffix = config::GetInstance()->GetPackSuffix();
            _pack_flag = false;
            _real_path = real_path;
            // file.txt -> ./pack_path/file.txt.lz
            _pack_path = pack_path + file.FileName() + pack_suffix;
            //./file.txt ->  /download/file.txt
            url = download_prefix + file.FileName();
            _atime = file.FileLastATime();
            _mtime = file.FileLastMTime();
            _fsize = file.FileSize();
            return true;
        }

        bool _pack_flag;
        std::string _pack_path;
        std::string _real_path;
        std::string url; // http中的url
        time_t _atime;
        time_t _mtime;
        size_t _fsize;
    } backupInfo;

    class DataManager
    {
    private:
        std::string _backup_file;
        pthread_rwlock_t _rwlock;
        std::unordered_map<std::string, backupInfo> _array;

    public:
        //确认当前用户
        DataManager(const std::string& Email)
        {
            _backup_file = config::GetInstance()->GetPackDictory();
            pthread_rwlock_init(&_rwlock, nullptr);
            InitLoad(Email);
        }

        bool Insert(const backupInfo &info) // 插入到_array中
        {
            pthread_rwlock_rdlock(&_rwlock);
            _array[info.url] = info; // 插入到_array中
            pthread_rwlock_unlock(&_rwlock);
            storage(); // 更新到备份文件里面
            return true;
        }

        bool Update(const backupInfo &info) // 更新到_array
        {
            pthread_rwlock_wrlock(&_rwlock);
            _array[info.url] = info;
            pthread_rwlock_unlock(&_rwlock);
            storage(); // 更新到备份文件里面
            return true;
        }

        bool GetOneByUrl(const std::string &url, backupInfo *info) // 查找
        {
            pthread_rwlock_wrlock(&_rwlock);
            auto it = _array.find(url); // 提高url进行查找
            if (it == _array.end())     // 找不到
            {
                std::cerr << "find backupInfo by url fail" << std::endl;
                pthread_rwlock_unlock(&_rwlock);
                return false;
            }
            *info = it->second; // 找到了,带出去
            pthread_rwlock_unlock(&_rwlock);
            return true;
        }

        bool GetOneByRealPath(const std::string &real_path, backupInfo *info)// 查找
        {
            pthread_rwlock_wrlock(&_rwlock);
            auto it = _array.begin();
            while (it != _array.end())
            {
                if (it->second._real_path == real_path)
                {
                    *info = it->second;
                    pthread_rwlock_unlock(&_rwlock);
                    return true;
                }
                ++it;
            }
            pthread_rwlock_unlock(&_rwlock);
            return true;
        }

        bool GetAll(std::vector<backupInfo> &_table) // 将所有备份文件描述结构体带出去
        {
            pthread_rwlock_wrlock(&_rwlock);
            for (auto &it : _array)
            {
                _table.push_back(it.second);
            }
            pthread_rwlock_unlock(&_rwlock);
            return true;
        }

        bool storage() // 更新备份文件
        {
            // 1.获取所有的备份文件结构体
            std::vector<backupInfo> _table;
            GetAll(_table);
            // 2.添加到Json::Value里面
            Json::Value root;
            for (int i = 0; i < _table.size(); ++i)
            {
                Json::Value item;
                item["_pack_flag"] = _table[i]._pack_flag;
                item["_real_path"] = _table[i]._real_path;
                item["_pack_path"] = _table[i]._pack_path;
                item["url"] = _table[i].url;
                item["_atime"] = _table[i]._atime;
                item["_mtime"] = _table[i]._mtime;
                item["_fsize"] = _table[i]._fsize;
                root.append(item); // 添加进去到root
            }
            // 3.将root进行序列化
            std::string str;
            JsonUtil::Serialize(root, &str);
            // 4.存到备份文件里
            FileUtil file(_backup_file);
            file.SetContent(str);
            return true;
        }

    private:
        bool InitLoad(const std::string Email)
        {
            //邮箱注册的账号是独一无二的,所以拿来做文件名最合适
            _backup_file = config::GetInstance()->GetBackupFile() + Email + ".data"; // 获取备份文件
            FileUtil file(_backup_file);
            if (file.IsExist() == false) // 第一次备份,备份文件还没有创建
            {
                return true;
            }
            std::string message; // 读取备份文件
            if (file.GetContent(&message) == false)
            {
                std::cerr << "read backup file fail" << std::endl;
                return false;
            }
            Json::Value root; // 反序列化
            JsonUtil::UnSerialize(message, &root);
            for (int i = 0; i < root.size(); ++i)
            {
                backupInfo info;
                info._pack_flag = root[i]["_pack_flag"].asBool();
                info._pack_path = root[i]["_pack_path"].asString();
                info._real_path = root[i]["_real_path"].asString();
                info.url = root[i]["url"].asString();
                info._fsize = root[i]["_fsize"].asInt();
                info._atime = root[i]["_atime"].asInt();
                info._mtime = root[i]["_mtime"].asInt();
                Insert(info);
            }
            return true;
        }
    };
}

#endif
